#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <dlib/mempool.h>
#include "phpserialize.h"

static int find_idx_of_string(char *buf, int len, char ch)
{
	int i = 0;
	for (; (i < len) && (buf[i] != ch); i++);
	return (i >= len) ? -1 : i; 
}

static int dlib_php_decode(dlib_php_handle handle, char *buf, int len)
{
	dlib_php_element_t *element = NULL;
	dlib_php_element_t *sub_elements = NULL;
	int tail = -1;
	char num[32] = {0};
	int colon = -1;
	int flag = 0;
	int count = 0;
	int idx = 0;
	int inc = 0;

	switch (buf[0]) {
		case 'b':
		case 'B':
			tail = find_idx_of_string(buf, len, ';');
			if ((buf[1] != ':') || (tail == -1)) {
				return -1;
			}

			memcpy(num, &buf[2], tail - 2);
			num[tail-2] = 0;

			if (dlib_php_set_bool(handle, atoi(num)) == -1) {
				return -1;
			}
			break;
		case 'i':
		case 'I':
			tail = find_idx_of_string(buf, len, ';');
			if ((buf[1] != ':') || (tail == -1)) {
				return -1;
			}

			memcpy(num, &buf[2], tail - 2);
			num[tail-2] = 0;

			if (dlib_php_set_integer(handle, atoi(num)) == -1) {
				return -1;
			}
			break;
		case 'd':
		case 'D':
			tail = find_idx_of_string(buf, len, ';');
			if ((buf[1] != ':') || (tail == -1)) {
				return -1;
			}

			memcpy(num, &buf[2], tail - 2);
			num[tail-2] = 0;

			if (dlib_php_set_double(handle, atof(num)) == -1) {
				return -1;
			}
			break;
		case 's':
		case 'S':
			colon = find_idx_of_string(&buf[2], len - 2, ':');
			if ((buf[1] != ':') || (colon == -1)) {
				return -1;
			}

			memcpy(num, &buf[2], colon);
			num[colon] = 0;

			tail = 5 + atoi(num) + colon;
			if ((buf[3+colon] != '\"') || (buf[tail-1] != '\"') || (buf[tail] != ';')) {
				return -1;
			}

			if (dlib_php_set_string(handle, &buf[4+colon], tail - colon - 5) == -1) {
				return -1;
			}
			break;
		case 'n':
		case 'N':
			tail = 1;
			if (buf[tail] != ';') {
				return -1;
			}

			if (dlib_php_set_null(handle) == -1) {
				return -1;
			}
			break;
		case 'a':
		case 'A':
			colon = find_idx_of_string(&buf[2], len - 2, ':');
			if ((buf[1] != ':') || (colon == -1) || (buf[colon+3] != '{')) {
				return -1;
			}

			for (tail = colon + 4, flag = 1; tail < len; tail++) {
				if (buf[tail] == '{') {
					flag++;
				}
				else if (buf[tail] == '}') {
					flag--;
				}

				if (flag == 0) {
					break;
				}
			}

			if (tail >= len) {
				return -1;
			}

			memcpy(num, &buf[2], colon);
			num[colon] = 0;

			count = atoi(num);
			if (count <= 0) {
				return -1;
			}

			if (dlib_php_set_array(handle, count) == -1) {
				return -1;
			}

			inc = 0;
			sub_elements = handle->a.elements;

			for (colon += 4, idx = 0; idx < (count * 2); colon += inc, idx++) {
				inc = dlib_php_decode((dlib_php_handle)&sub_elements[idx], &buf[colon], len - colon);
				if (inc == -1) {
					dfree(sub_elements);
					return -1;
				}
			}
			break;
		case 'o':
		case 'O':
			colon = find_idx_of_string(&buf[2], len - 2, ':');
			if ((buf[1] != ':') || (colon == -1)) {
				return -1;
			}

			memcpy(num, &buf[2], colon);
			num[colon] = 0;

			count = atoi(num);
			if ((count <= 0) || (buf[colon+3] != '\"') ||
					(buf[colon+count+4] != '\"') || (buf[colon+count+5] != ':')) {
				return -1;
			}

			element = dlib_php_get_element(handle);
			if (element != NULL) {
				element->o.name = (char*)dmalloc(sizeof(char) * (count + 1));
				if (element->o.name == NULL) {
					return -1;
				}

				memcpy(element->o.name, &buf[colon+4], count);
				element->o.name[count] = 0;
				element->t = DLIB_PHP_DATATYPE_OBJECT;
			}

			tail = colon + count + 6;
			colon = find_idx_of_string(&buf[tail], len - tail, ':');
			if (colon == -1) {
				if (element != NULL) {
					dfree(element->o.name);
					return -1;
				}
			}

			memcpy(num, &buf[tail], colon);
			num[colon] = 0;

			count = atoi(num);
			if ((count <= 0) || (buf[tail+colon] != ':') || (buf[tail+colon+1] != '{')) {
				if (element != NULL) {
					dfree(element->o.name);
					return -1;
				}
			}

			colon += tail;
			for (tail = colon + 2, flag = 1; tail < len; tail++) {
				if (buf[tail] == '{') {
					flag++;
				}
				else if (buf[tail] == '}') {
					flag--;
				}

				if (flag == 0) {
					break;
				}
			}

			if (tail >= len) {
				if (element != NULL) {
					dfree(element->o.name);
					return -1;
				}
			}

			if (element != NULL) {
				sub_elements = (dlib_php_element_t*)dmalloc(sizeof(dlib_php_element_t) * count * 2);
				if (sub_elements == NULL) {
					dfree(element->o.name);
					return -1;
				}

				for (colon += 2, idx = 0, inc = 0; idx < (count * 2); colon += inc, idx++) {
					inc = dlib_php_decode((dlib_php_handle)&sub_elements[idx], &buf[colon], len - colon);
					if (inc == -1) {
						dfree(sub_elements);
						dfree(element->o.name);
						return -1;
					}
				}

				element->o.count = count;
				element->o.members = sub_elements;
			}

			break;
	}

	return tail + 1;
}

static dlib_php_handle dlib_php_unserialize_internal(char *buf, int len)
{
	dlib_php_handle handle = NULL;

	handle = (dlib_php_handle)dmalloc(sizeof(dlib_php_element_t));
	if (handle == NULL) {
		return NULL;
	}

	if (dlib_php_decode(handle, buf, len) == -1) {
		dfree(handle);
		return NULL;
	}

	return handle; 
}

dlib_php_handle dlib_php_unserialize(char *buf, int len)
{
	if ((buf != NULL) || (len > 0)) {
		return dlib_php_unserialize_internal(buf, len);
	}
	return DLIB_PHP_INVALID_HANDLE;
}

static int dlib_php_encode(dlib_php_handle handle, char *buf, int *len)
{
	dlib_php_element_t *element = dlib_php_get_element(handle);
	int tail = 0;
	int res = -1;
	int i = 0;

	switch (element->t) {
		case DLIB_PHP_DATATYPE_BOOL:
			res = snprintf(buf, *len, "b:%d;", element->b);
			if (res == -1) {
				return -1;
			}
			*len -= res;
			tail += res;
			break;
		case DLIB_PHP_DATATYPE_INT:
			res = snprintf(buf, *len, "i:%d;", element->i);
			if (res == -1) {
				return -1;
			}
			*len -= res;
			tail += res;
			break;
		case DLIB_PHP_DATATYPE_DOUBLE:
			res = snprintf(buf, *len, "d:%f;", element->d);
			if (res == -1) {
				return -1;
			}
			*len -= res;
			tail += res;
			break;
		case DLIB_PHP_DATATYPE_STRING:
			res = snprintf(buf, *len, "s:%d:\"%s\";", strlen(element->s), element->s);
			if (res == -1) {
				return -1;
			}
			*len -= res;
			tail += res;
			break;
		case DLIB_PHP_DATATYPE_NULL:
			res = snprintf(buf, *len, "N;");
			if (res == -1) {
				return -1;
			}
			*len -= res;
			tail += res;
			break;
		case DLIB_PHP_DATATYPE_ARRAY:
			res = snprintf(buf, *len, "a:%d:{", element->a.count);
			if (res == -1) {
				return -1;
			}

			*len -= res;
			tail += res;

			for (i = 0; i < (element->a.count * 2); i++) {
				res = dlib_php_encode((dlib_php_handle)&element->a.elements[i], &buf[strlen(buf)], len);
				if (res == -1) {
					return -1;
				}
				*len -= res;
				tail += res;
			}

			res = snprintf(&buf[strlen(buf)], *len, "}");
			if (res == -1) {
				return -1;
			}

			*len -= res;
			tail += res;
			break;
		case DLIB_PHP_DATATYPE_OBJECT:
			res = snprintf(buf, *len, "O:%d:\"%s\":%d:{", strlen(element->o.name), element->o.name, element->o.count);
			if (res == -1) {
				return -1;
			}

			*len -= res;
			tail += res;

			for (i = 0; i < (element->o.count * 2); i++) {
				res = dlib_php_encode((dlib_php_handle)&element->o.members[i], &buf[strlen(buf)], len);
				if (res == -1) {
					return -1;
				}
				*len -= res;
				tail += res;
			}

			res = snprintf(&buf[strlen(buf)], *len, "}");
			if (res == -1) {
				return -1;
			}

			*len -= res;
			tail += res;
			break;
		default:
			break;
	}
	return tail;
}

static int dlib_php_serialize_internal(dlib_php_handle handle, char *buf, int *len)
{
	return dlib_php_encode(handle, buf, len);
}

int dlib_php_serialize(dlib_php_handle handle, char *buf, int *len)
{
	if ((handle != NULL) && (buf != NULL) && (len != NULL) && (*len > 0)) {
		return dlib_php_serialize_internal(handle, buf, len);
	}
	return -1;
}

dlib_php_handle dlib_php_create_bool(int b)
{
	dlib_php_element_t *element = NULL;

	element = (dlib_php_element_t*)dmalloc(sizeof(dlib_php_element_t));
	if (element != NULL) {
		element->b = b;
		element->t = DLIB_PHP_DATATYPE_BOOL;
	}
	return (dlib_php_handle)element;
}

dlib_php_handle dlib_php_create_integer(int i)
{
	dlib_php_element_t *element = NULL;

	element = (dlib_php_element_t*)dmalloc(sizeof(dlib_php_element_t));
	if (element != NULL) {
		element->i = i;
		element->t = DLIB_PHP_DATATYPE_INT;
	}
	return (dlib_php_handle)element;
}

dlib_php_handle dlib_php_create_double(double d)
{
	dlib_php_element_t *element = NULL;

	element = (dlib_php_element_t*)dmalloc(sizeof(dlib_php_element_t));
	if (element != NULL) {
		element->d = d;
		element->t = DLIB_PHP_DATATYPE_DOUBLE;
	}
	return (dlib_php_handle)element;
}

dlib_php_handle dlib_php_create_string(char *s, int len)
{
	dlib_php_element_t *element = NULL;

	if ((s == NULL) || (len <= 0)) {
		return NULL;
	}

	element = (dlib_php_element_t*)dmalloc(sizeof(dlib_php_element_t));
	if (element == NULL) {
		return NULL;
	}

	element->s = (char*)dmalloc(sizeof(char) * (len + 1));
	if (element->s == NULL) {
		dfree(element);
		return NULL;
	}

	memcpy(element->s, s, len);
	element->s[len] = 0;
	element->t = DLIB_PHP_DATATYPE_STRING;

	return (dlib_php_handle)element;
}

dlib_php_handle dlib_php_create_null(void)
{
	dlib_php_element_t *element = NULL;

	element = (dlib_php_element_t*)dmalloc(sizeof(dlib_php_element_t));
	if (element != NULL) {
		element->n = 0;
		element->t = DLIB_PHP_DATATYPE_NULL;
	}
	return (dlib_php_handle)element;
}

dlib_php_handle dlib_php_create_array(int count)
{
	dlib_php_element_t *element = NULL;

	if (count <= 0) {
		return NULL;
	}

	element = (dlib_php_element_t*)dmalloc(sizeof(dlib_php_element_t));
	if (element == NULL) {
		return NULL;
	}

	element->a.count = count;
	element->a.elements = (dlib_php_element_t*)dmalloc(sizeof(dlib_php_element_t) * element->a.count * 2);
	if (element->a.elements == NULL) {
		dfree(element);
		return NULL;
	}

	return (dlib_php_handle)element;
}

dlib_php_handle dlib_php_create_object(char *name, int len, int count)
{
	dlib_php_element_t *element = NULL;

	if ((name == NULL) || (len <= 0) || (count <= 0)) {
		return NULL;
	}

	element = (dlib_php_element_t*)dmalloc(sizeof(dlib_php_element_t));
	if (element == NULL) {
		return NULL;
	}

	element->o.name = (char*)dmalloc(sizeof(char) * (len + 1));
	if (element->o.name == NULL) {
		dfree(element);
		return NULL;
	}

	memcpy(element->o.name, name, len);
	element->o.name[len] = 0;

	element->o.count = count;
	element->o.members = (dlib_php_element_t*)dmalloc(sizeof(dlib_php_element_t) * element->o.count * 2);
	if (element->o.members == NULL) {
		dfree(element->o.name);
		dfree(element);
		return NULL;
	}

	return (dlib_php_handle)element;
}

static void dlib_php_release_handle_internal(dlib_php_handle handle)
{
	dlib_php_element_t *element = dlib_php_get_element(handle);
	dlib_php_element_t *elements = NULL;
	int i = 0;

	switch (element->t) {
		case DLIB_PHP_DATATYPE_STRING:
			dfree(element->s);
			break;
		case DLIB_PHP_DATATYPE_ARRAY:
			elements = element->a.elements;
			for (i = 1; i < (element->a.count * 2); i += 2) {
				dlib_php_release_handle_internal((dlib_php_handle)&elements[i]);
			}
			dfree(elements);
			break;
		case DLIB_PHP_DATATYPE_OBJECT:
			dfree(element->o.name);
			elements = element->o.members;
			for (i = 1; i < (element->o.count * 2); i += 2) {
				dlib_php_release_handle_internal((dlib_php_handle)&elements[i]);
			}
			dfree(elements);
			break;
		default:
			break;
	}
}

void dlib_php_release_handle(dlib_php_handle handle)
{
	if (handle != NULL) {
		dlib_php_release_handle_internal(handle);
		dfree(handle);
	}
}

int dlib_php_set_bool(dlib_php_handle handle, int b)
{
	if (handle != NULL) {
		dlib_php_release_handle_internal(handle);
		handle->b = b;
		handle->t = DLIB_PHP_DATATYPE_BOOL;
		return 0;
	}
	return -1;
}

int dlib_php_set_integer(dlib_php_handle handle, int i)
{
	if (handle != NULL) {
		dlib_php_release_handle_internal(handle);
		handle->i = i;
		handle->t = DLIB_PHP_DATATYPE_INT;
		return 0;
	}
	return -1;
}

int dlib_php_set_double(dlib_php_handle handle, double d)
{
	if (handle != NULL) {
		dlib_php_release_handle_internal(handle);
		handle->d = d;
		handle->t = DLIB_PHP_DATATYPE_DOUBLE;
		return 0;
	}
	return -1;
}

int dlib_php_set_string(dlib_php_handle handle, char *buf, int len)
{
	char *str = NULL;

	if ((handle == NULL) || (buf == NULL) || (len <= 0)) {
		return -1;
	}

	if (handle->t != DLIB_PHP_DATATYPE_STRING) {
		str = (char*)dmalloc(sizeof(char) * (len + 1));
		if (str == NULL) {
			return -1;
		}

		dlib_php_release_handle_internal(handle);
	}
	else if (strlen(handle->s) < (unsigned int)len) {
		str = (char*)drealloc(handle->s, sizeof(char) * (len + 1));
		if (str == NULL) {
			return -1;
		}
	}

	memcpy(str, buf, len);
	str[len] = 0;

	handle->s = str;
	handle->t = DLIB_PHP_DATATYPE_STRING;

	return 0;
}

int dlib_php_set_null(dlib_php_handle handle)
{
	if (handle != NULL) {
		dlib_php_release_handle_internal(handle);
		handle->n = 0;
		handle->t = DLIB_PHP_DATATYPE_NULL;
		return 0;
	}
	return -1;
}

int dlib_php_set_array(dlib_php_handle handle, int count)
{
	dlib_php_element_t *elements = NULL;

	if ((handle == NULL) || (count <= 0)) {
		return -1;
	}

	if (handle->t != DLIB_PHP_DATATYPE_ARRAY) {
		elements = (dlib_php_element_t*)dmalloc(sizeof(dlib_php_element_t) * count * 2);
		if (elements == NULL) {
			return -1;
		}

		dlib_php_release_handle_internal(handle);
	}
	else if (handle->a.count < count) {
		elements = (dlib_php_element_t*)drealloc(handle->a.elements, sizeof(dlib_php_element_t) * count * 2);
		if (elements == NULL) {
			return -1;
		}
	}

	handle->a.count = count;
	handle->a.elements = elements;
	handle->t = DLIB_PHP_DATATYPE_ARRAY;

	return 0;
}

int dlib_php_set_array_element_bool(dlib_php_handle handle, int idx, char *key, int b)
{
	if ((handle == NULL) || (handle->t != DLIB_PHP_DATATYPE_ARRAY) ||
			(idx < 0) || (idx >= handle->a.count)) {
		return -1;
	}

	if (((key == NULL) && (dlib_php_set_integer((dlib_php_handle)&handle->a.elements[idx], idx) == 0)) ||
			((key != NULL) && (dlib_php_set_string((dlib_php_handle)&handle->a.elements[idx], key, strlen(key))))) {
		return dlib_php_set_bool((dlib_php_handle)&handle->a.elements[idx+1], b);
	}

	return -1;
}

int dlib_php_set_array_element_integer(dlib_php_handle handle, int idx, char *key, int i)
{
	if ((handle == NULL) || (handle->t != DLIB_PHP_DATATYPE_ARRAY) ||
			(idx < 0) || (idx >= handle->a.count)) {
		return -1;
	}

	if (((key == NULL) && (dlib_php_set_integer((dlib_php_handle)&handle->a.elements[idx], idx) == 0)) ||
			((key != NULL) && (dlib_php_set_string((dlib_php_handle)&handle->a.elements[idx], key, strlen(key))))) {
		return dlib_php_set_integer((dlib_php_handle)&handle->a.elements[idx+1], i);
	}

	return -1;
}

int dlib_php_set_array_element_double(dlib_php_handle handle, int idx, char *key, double d)
{
	if ((handle == NULL) || (handle->t != DLIB_PHP_DATATYPE_ARRAY) ||
			(idx < 0) || (idx >= handle->a.count)) {
		return -1;
	}

	if (((key == NULL) && (dlib_php_set_integer((dlib_php_handle)&handle->a.elements[idx], idx) == 0)) ||
			((key != NULL) && (dlib_php_set_string((dlib_php_handle)&handle->a.elements[idx], key, strlen(key))))) {
		return dlib_php_set_double((dlib_php_handle)&handle->a.elements[idx+1], d);
	}

	return -1;
}

int dlib_php_set_array_element_string(dlib_php_handle handle, int idx, char *key, char *s, int len)
{
	if ((handle == NULL) || (handle->t != DLIB_PHP_DATATYPE_ARRAY) ||
			(idx < 0) || (idx >= handle->a.count)) {
		return -1;
	}

	if (((key == NULL) && (dlib_php_set_integer((dlib_php_handle)&handle->a.elements[idx], idx) == 0)) ||
			((key != NULL) && (dlib_php_set_string((dlib_php_handle)&handle->a.elements[idx], key, strlen(key))))) {
		return dlib_php_set_string((dlib_php_handle)&handle->a.elements[idx+1], s, len);
	}

	return -1;
}

int dlib_php_set_array_element_null(dlib_php_handle handle, int idx, char *key)
{
	if ((handle == NULL) || (handle->t != DLIB_PHP_DATATYPE_ARRAY) ||
			(idx < 0) || (idx >= handle->a.count)) {
		return -1;
	}

	if (((key == NULL) && (dlib_php_set_integer((dlib_php_handle)&handle->a.elements[idx], idx) == 0)) ||
			((key != NULL) && (dlib_php_set_string((dlib_php_handle)&handle->a.elements[idx], key, strlen(key))))) {
		return dlib_php_set_null((dlib_php_handle)&handle->a.elements[idx+1]);
	}

	return -1;
}

int dlib_php_set_array_element_array(dlib_php_handle handle, int idx, char *key, int count)
{
	if ((handle == NULL) || (handle->t != DLIB_PHP_DATATYPE_ARRAY) ||
			(idx < 0) || (idx >= handle->a.count)) {
		return -1;
	}

	if (((key == NULL) && (dlib_php_set_integer((dlib_php_handle)&handle->a.elements[idx], idx) == 0)) ||
			((key != NULL) && (dlib_php_set_string((dlib_php_handle)&handle->a.elements[idx], key, strlen(key))))) {
		return dlib_php_set_array((dlib_php_handle)&handle->a.elements[idx+1], count);
	}

	return -1;
}

int dlib_php_set_array_element_object(dlib_php_handle handle, int idx, char *key, char *name, int len, int count)
{
	if ((handle == NULL) || (handle->t != DLIB_PHP_DATATYPE_ARRAY) ||
			(idx < 0) || (idx >= handle->a.count)) {
		return -1;
	}

	if (((key == NULL) && (dlib_php_set_integer((dlib_php_handle)&handle->a.elements[idx], idx) == 0)) ||
			((key != NULL) && (dlib_php_set_string((dlib_php_handle)&handle->a.elements[idx], key, strlen(key))))) {
		return dlib_php_set_object((dlib_php_handle)&handle->a.elements[idx+1], name, len, count);
	}

	return -1;
}

int dlib_php_set_object(dlib_php_handle handle, char *name, int len, int count)
{
	char *str = NULL;
	dlib_php_element_t * elements = NULL;

	if ((handle == NULL) || (name ==  NULL) || (len <= 0) || (count <= 0)) {
		return -1;
	}

	if (handle->t != DLIB_PHP_DATATYPE_OBJECT) {
		str = (char*)dmalloc(sizeof(char) * (len + 1));
		if (str == NULL) {
			return -1;
		}

		elements = (dlib_php_element_t*)dmalloc(sizeof(dlib_php_element_t) * count * 2);
		if (elements == NULL) {
			return -1;
		}

		dlib_php_release_handle_internal(handle);
	}
	else {
		if (strlen(handle->o.name) < (unsigned int)len) {
			str = (char*)drealloc(handle->o.name, sizeof(char) * (len + 1));
			if (str == NULL) {
				return -1;
			}
		}

		if (handle->o.count < count) {
			elements = (dlib_php_element_t*)drealloc(handle->o.members, sizeof(dlib_php_element_t) * count * 2);
			if (elements == NULL) {
				return -1;
			}
		}
	}

	memcpy(str, name, len);
	str[len] = 0;

	handle->o.name = str;
	handle->o.count = count;
	handle->o.members = elements;
	handle->t = DLIB_PHP_DATATYPE_OBJECT;

	return 0;
}

int dlib_php_set_object_member_bool(dlib_php_handle handle, int idx, char *name, int b)
{
	if ((handle == NULL) || (handle->t != DLIB_PHP_DATATYPE_OBJECT) ||
			(idx < 0) || (idx >= handle->o.count) || (name == NULL)) {
		return -1;
	}

	if (dlib_php_set_string((dlib_php_handle)&handle->o.members[idx], name, strlen(name)) == 0) {
		return dlib_php_set_bool((dlib_php_handle)&handle->o.members[idx+1], b);
	}

	return -1;
}

int dlib_php_set_object_member_integer(dlib_php_handle handle, int idx, char *name, int i)
{
	if ((handle == NULL) || (handle->t != DLIB_PHP_DATATYPE_OBJECT) ||
			(idx < 0) || (idx >= handle->o.count) || (name == NULL)) {
		return -1;
	}

	if (dlib_php_set_string((dlib_php_handle)&handle->o.members[idx], name, strlen(name)) == 0) {
		return dlib_php_set_integer((dlib_php_handle)&handle->o.members[idx+1], i);
	}

	return -1;
}

int dlib_php_set_object_member_double(dlib_php_handle handle, int idx, char *name, double d)
{
	if ((handle == NULL) || (handle->t != DLIB_PHP_DATATYPE_OBJECT) ||
			(idx < 0) || (idx >= handle->o.count) || (name == NULL)) {
		return -1;
	}

	if (dlib_php_set_string((dlib_php_handle)&handle->o.members[idx], name, strlen(name)) == 0) {
		return dlib_php_set_double((dlib_php_handle)&handle->o.members[idx+1], d);
	}

	return -1;
}

int dlib_php_set_object_member_string(dlib_php_handle handle, int idx, char *name, char *s, int len)
{
	if ((handle == NULL) || (handle->t != DLIB_PHP_DATATYPE_OBJECT) ||
			(idx < 0) || (idx >= handle->o.count) || (name == NULL)) {
		return -1;
	}

	if (dlib_php_set_string((dlib_php_handle)&handle->o.members[idx], name, strlen(name)) == 0) {
		return dlib_php_set_string((dlib_php_handle)&handle->o.members[idx+1], s, len);
	}

	return -1;
}

int dlib_php_set_object_member_null(dlib_php_handle handle, int idx, char *name)
{
	if ((handle == NULL) || (handle->t != DLIB_PHP_DATATYPE_OBJECT) ||
			(idx < 0) || (idx >= handle->o.count) || (name == NULL)) {
		return -1;
	}

	if (dlib_php_set_string((dlib_php_handle)&handle->o.members[idx], name, strlen(name)) == 0) {
		return dlib_php_set_null((dlib_php_handle)&handle->o.members[idx+1]);
	}

	return -1;
}

int dlib_php_set_object_member_array(dlib_php_handle handle, int idx, char *name, int count)
{
	if ((handle == NULL) || (handle->t != DLIB_PHP_DATATYPE_OBJECT) ||
			(idx < 0) || (idx >= handle->o.count) || (name == NULL)) {
		return -1;
	}

	if (dlib_php_set_string((dlib_php_handle)&handle->o.members[idx], name, strlen(name)) == 0) {
		return dlib_php_set_array((dlib_php_handle)&handle->o.members[idx+1], count);
	}

	return -1;
}

int dlib_php_set_object_member_object(dlib_php_handle handle, int idx, char *name, char *subname, int len, int count)
{
	if ((handle == NULL) || (handle->t != DLIB_PHP_DATATYPE_OBJECT) ||
			(idx < 0) || (idx >= handle->o.count) || (name == NULL)) {
		return -1;
	}

	if (dlib_php_set_string((dlib_php_handle)&handle->o.members[idx], name, strlen(name)) == 0) {
		return dlib_php_set_object((dlib_php_handle)&handle->o.members[idx+1], subname, len, count);
	}

	return -1;
}

dlib_php_element_t * dlib_php_get_element(dlib_php_handle handle)
{
	return handle;
}

int dlib_php_get_bool(dlib_php_handle handle)
{
	if ((handle != NULL) && (handle->t == DLIB_PHP_DATATYPE_BOOL)) {
		return handle->b;
	}
	return 0;
}

int dlib_php_get_integer(dlib_php_handle handle)
{
	if ((handle != NULL) && (handle->t == DLIB_PHP_DATATYPE_INT)) {
		return handle->i;
	}
	return 0;
}

double dlib_php_get_double(dlib_php_handle handle)
{
	if ((handle != NULL) && (handle->t == DLIB_PHP_DATATYPE_DOUBLE)) {
		return handle->d;
	}
	return 0;
}

char * dlib_php_get_string(dlib_php_handle handle)
{
	if ((handle != NULL) && (handle->t != DLIB_PHP_DATATYPE_STRING)) {
		return handle->s;
	}
	return NULL;
}

int dlib_php_get_null(dlib_php_handle handle)
{
	return 0;
}

int dlib_php_get_array_count(dlib_php_handle handle)
{
	if ((handle != NULL) && (handle->t == DLIB_PHP_DATATYPE_ARRAY)) {
		return handle->a.count;
	}
	return 0;
}

dlib_php_element_t * dlib_php_get_array_element_by_pos(dlib_php_handle handle, int idx)
{
	if ((handle != NULL) && (handle->t == DLIB_PHP_DATATYPE_ARRAY)) {
		return &handle->a.elements[2*idx+1];
	}
	return NULL;
}

dlib_php_element_t * dlib_php_get_array_element_by_key(dlib_php_handle handle, char *key)
{
	int i = 0;

	if ((handle != NULL) && (handle->t == DLIB_PHP_DATATYPE_ARRAY)) {
		for (i = 0; i < handle->a.count; i++) {
			switch (handle->a.elements[i].t) {
				case DLIB_PHP_DATATYPE_STRING:
					if (strcasecmp(handle->a.elements[i].s, key) == 0) {
						return &handle->a.elements[i+1];
					}
					break;
				case DLIB_PHP_DATATYPE_INT:
					if (handle->a.elements[i].i == atoi(key)) {
						return &handle->a.elements[i+1];
					}
					break;
				default:
					break;
			}
		}
	}
	return NULL;
}

char * dlib_php_get_object_name(dlib_php_handle handle)
{
	if ((handle != NULL) && (handle->t == DLIB_PHP_DATATYPE_OBJECT)) {
		return handle->o.name;
	}
	return NULL;
}

int dlib_php_get_object_count(dlib_php_handle handle)
{
	if ((handle != NULL) && (handle->t == DLIB_PHP_DATATYPE_OBJECT)) {
		return handle->o.count;
	}
	return 0;
}

dlib_php_element_t * dlib_php_get_object_member(dlib_php_handle handle, char *name)
{
	int i = 0;

	if ((handle != NULL) && (handle->t == DLIB_PHP_DATATYPE_OBJECT)) {
		for (i = 0; i < handle->o.count; i++) {
			if (handle->o.members[i].t == DLIB_PHP_DATATYPE_STRING) {
				if (strcasecmp(&handle->o.members[i].s[strlen(handle->o.name)+2], name) == 0) {
					return &handle->o.members[i+1];
				}
			}
		}
	}
	return NULL;
}
